/*
 * Copyright 2009 Johnson Consulting Services
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.johnsoncs.gwt.widgets.samples.server.mock;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.johnsoncs.gwt.application.client.model.Data;
import com.johnsoncs.gwt.widgets.client.dynamictable.Row;
import com.johnsoncs.gwt.widgets.client.dynamictable.SortInfo;
import com.johnsoncs.gwt.widgets.client.dynamictable.Selection.SelectionType;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportException;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportRequest;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportRuntimeException;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportStatus;
import com.johnsoncs.gwt.widgets.client.util.Callback;
import com.johnsoncs.gwt.widgets.samples.client.mock.DbInitStatus;
import com.johnsoncs.gwt.widgets.samples.client.mock.MockFilter;
import com.johnsoncs.gwt.widgets.samples.client.mock.MockRemoteServiceException;
import com.johnsoncs.gwt.widgets.samples.client.mock.MockRemoteTableModel;
import com.johnsoncs.gwt.widgets.samples.client.mock.MyRowObject;
import com.johnsoncs.gwt.widgets.server.export.ExportModel;
import com.johnsoncs.gwt.widgets.server.export.ExportServlet;
import com.johnsoncs.gwt.widgets.server.export.ExportStatusProxy;
import com.johnsoncs.gwt.widgets.server.export.ExportStorage;
import com.johnsoncs.gwt.widgets.server.export.impl.DiskStorage;

public class MockRemoteTableModelImpl extends ExportServlet<MyRowObject> implements MockRemoteTableModel {

	private class MyExportModel implements ExportModel<MyRowObject> {
		final List<MyRowObject> rows;

		public MyExportModel(final List<MyRowObject> rows) {
			this.rows = rows;
		}

		@Override
		public void export(final ExportRequest<MyRowObject> request,
				final Callback<MyRowObject> rowCallback) {

			// TODO need to address how selection state is going to work without doing a full table scan
			for (final MyRowObject m : rows) {
				if (isSelected(m, request)) {
					rowCallback.exec(m);
				}
			}
		}
	}

	{
		TableModelDao.getInstance().beginInitialization();
	}

	// NOTE: This is a really bad way to do it.  In a real deployment environment you probably have a database to store this stuff in
	private static Map<String, ExportStatus> statusMap = new ConcurrentHashMap<String, ExportStatus>();
	private static final long serialVersionUID = 1L;

	/* (non-Javadoc)
	* @see com.johnsoncs.gwt.widgets.samples.client.mock.MockRemoteTableModel#getData2()
	*/
	@Override
	public Data getData() throws MockRemoteServiceException {
		final Data mixed = new Data();
		mixed.add("bob");
		mixed.add(42);
		mixed.set("cows", "go moo");
		mixed.set("numberOfCows", 123);

		final Data nested = new Data();
		nested.set("nested1", "I are nested");
		nested.set("another", "hurrr, nested too");
		mixed.set("child", nested);

		final Data nestedList = new Data();
		nestedList.add(2);
		nestedList.add(4);
		nestedList.add(6);
		nestedList.add(8);
		nested.set("list", nestedList);

		final Data evenMoreNested = new Data();
		evenMoreNested.set("blah", "blort");
		nestedList.add(evenMoreNested);

		return mixed;
	}

	/* (non-Javadoc)
	 * @see com.johnsoncs.gwt.widgets.server.export.ExportServlet#getExportModel()
	 */
	@Override
	@SuppressWarnings("unchecked")
	public ExportModel<MyRowObject> getExportModel(final ExportRequest<MyRowObject> request) {
		try {
			// TODO implement export method that doesn't require a full table scan
			final TableModelDao tmd = TableModelDao.getInstance();
			final List<MyRowObject> rows = tmd.requestRows(0, tmd.ROW_COUNT, request.getSort(), (MockFilter) request
					.getFilter());
			return new MyExportModel(rows);
		} catch (final MockRemoteServiceException e) {
			throw new ExportRuntimeException(e);
		}
	}

	@Override
	public ExportStatus getExportStatus(final String exportId) throws ExportException {
		return statusMap.get(getStatusKey(exportId));
	}

	/* (non-Javadoc)
	 * @see com.johnsoncs.gwt.widgets.server.export.ExportServlet#getExportStatusProxy()
	 */
	@Override
	public ExportStatusProxy getExportStatusProxy() {
		return new ExportStatusProxy() {

			@Override
			public void deleteExportStatus(final String exportId) {
				statusMap.remove(exportId);
			}

			@Override
			public ExportStatus getExportStatus(final String exportId) {
				return statusMap.get(exportId);
			}

			@Override
			public void setExportStatus(final ExportStatus status) {
				statusMap.put(status.getExportId(), status);
			}

		};
	}

	/* (non-Javadoc)
	 * @see com.johnsoncs.gwt.widgets.server.export.ExportServlet#getExportStorage()
	 */
	@Override
	public ExportStorage getExportStorage() {
		return new DiskStorage(System.getProperty("java.io.tmpdir"));
	}

	/* (non-Javadoc)
	 * @see com.johnsoncs.gwt.widgets.samples.client.mock.MockRemoteTableModel#getInitStatus()
	 */
	@Override
	public DbInitStatus getInitStatus() {
		final TableModelDao tmd = TableModelDao.getInstance();
		final boolean b = tmd.isDbInitialized();
		int pct;
		if (tmd.ROW_COUNT > 0) {
			pct = (tmd.getRowsInserted() * 100) / tmd.ROW_COUNT;
		} else {
			pct = 100;
		}
		return new DbInitStatus(b, pct);
	}

	private String getStatusKey(final String exportId) {
		return "EXPORTSTATUS" + exportId;
	}

	private boolean isSelected(final MyRowObject m, final ExportRequest<MyRowObject> request) {
		return (request.getSelectionType() == SelectionType.EXCLUSIVE && !request.getSelectedIds().contains(m.getId()))
				|| (request.getSelectionType() == SelectionType.INCLUSIVE && request.getSelectedIds().contains(
				m.getId()));
	}

	private void pause() {
		try {
			Thread.sleep(250);
		} catch (final InterruptedException ie) {
			Thread.currentThread().interrupt();
		}
	}

	@Override
	public Integer requestRowCount(final MockFilter filter) throws MockRemoteServiceException {
		pause();
		final Integer result = TableModelDao.getInstance().requestRowCount(filter);
		return result;
	}

	@Override
	public List<Row<MyRowObject>> requestRows(final int start, final int count, final List<SortInfo> sortInfo,
			final MockFilter filter) throws MockRemoteServiceException {
		pause();
		final List<Row<MyRowObject>> result = new ArrayList<Row<MyRowObject>>();
		final List<MyRowObject> rows = TableModelDao.getInstance().requestRows(start, count, sortInfo, filter);

		for (int i = 0; i < rows.size(); i++) {
			final Row<MyRowObject> r = new Row<MyRowObject>(start + i, rows.get(i));
			result.add(r);
		}
		return result;
	}
}
